#!/usr/bin/python


import sys
import os

from constants import *
import dbus
from pyfuncs import *
from time import *
from os import *
from my_exceptions import *
from datetime import datetime

import logging
logger = logging.getLogger("Interface")
logger.setLevel(logging.DEBUG+3)


# Facilities
EMPTY_NODE = dbus.Struct([NODE_EMPTY, "", "", DEFAULT_ONTOLOGY_URI])




"""
~~~~~~~~~~~~~~~~~~~~ NOTES ON THIS CLASS ~~~~~~~~~~~~~~~~~~~

# 1. It is very important to close every initialized iterator (iterator.close()). Indeed, an open iterator seems to block the dbus communication to Soprano, causing the access to be "denied" to other methods, even if they apply on different objects like on a model, e.g. model.deleteStatement().

"""





#**********************************************************#

class Interface (object): # Inherits from object (necessary to use the Singleton Design Pattern).
	
	
	#~~~~~~~~~~~~~~~~~~~~~~~~~ BEGIN  ~~~~~~~~~~~~~~~~~~~~~~~~~#
	
	#~ This is the Python code for an advanced Singleton Design Pattern use. ~#
	#~ see http://en.wikipedia.org/wiki/Singleton_pattern#Python for more information (available on the 2008-07-07). ~#
	#~ If you want to inherit from Interface, you should study the subject and possibly rewrite it (see the same web page for details). ~#
	
	# static attributes of the class Interface
	instance = None
	model = None
	
	# standard construction method in Python
	def __new__(interfaceClass, service_name="org.kde.NepomukStorage", model_name="/org/soprano/Server/models/main"):
		"""
			:Parameters:
				`service_name` : str
					The name of the service that is to be called for storage purpose (mainly adding/retrieval of statements, querying).
				`model_name` : str
					The dbus path to the soprano model that we are going to work on.
				:Raises `dbus.exceptions.DBusException`: if the service_name is not accessible.
		"""
		
		logger.debug("Interface.__new__")
		if interfaceClass.instance is None:
			
			# initializations (run only once)
			logger.debug("\t(first time)")
			self_obj = object.__new__(interfaceClass)
			interfaceClass.instance = self_obj
			
			self_obj.service_name = service_name
			
			self_obj.model = dbus.SessionBus().get_object(self_obj.service_name, model_name)
			
		return interfaceClass.instance
	
	#~~~~~~~~~~~~~~~~~~~~~~~~~  END   ~~~~~~~~~~~~~~~~~~~~~~~~~#
	
	
	def __init__(self, service_name="org.kde.NepomukStorage", model_name="/org/soprano/Server/models/main"):
		""" See the __new__() method for information.
		"""
		
		logger.debug("Interface.__init__")
		
		self.derivationTable = {}
		
############################################################

	def getUniqueId(self):
		""" Returns an ID, unique in the model on which we work.
			:Returns: A unique 20 characters-long ID.
		"""
		
		while(True):
			
			new_id = PATH_NEPOMUK+random_string(20)
			# let's request the model if a resource with that name already exists
			#print new_id
			query = "SELECT * WHERE { <" + new_id + "> ?rel ?obj }"
			query_result_iterator = self.executeQuery(query)
			
			# if there is at least one answer to the request (iterator.next() succeeds on the first try), the resource already exists and we have to generate a new one
			if (not query_result_iterator.next()):
				query_result_iterator.close()
				#print "does not exist... yet"
				return new_id
			
			query_result_iterator.close()
		
############################################################
	
	# /!\ See note 1 on top of that document.
	def executeQuery(self, query, queryLang=QUERYLANG_SPARQL):
		""" Executes a query on self.model, which will often be in SPARQL.
			:Parameters:
				`query` : str
					The query to perform.
				`queryLang` : str
					The URI of a query language.
			:Returns: A soprano QueryResultIterator. Pay attention when using this kind of iterator: always close your iterators before you perform other operations on the same model !
		"""
		
		#print "query = " + query + " ; queryLang = " + queryLang
		query_result_iterator_name = self.model.executeQuery(query, queryLang)
		query_result_iterator = dbus.SessionBus().get_object(self.service_name, query_result_iterator_name)
		return query_result_iterator

############################################################

	def executeQueryDisplayableResult(self, query, queryLang=QUERYLANG_SPARQL):
		""" Executes a query on self.model, which will often be in SPARQL.
			:Parameters:
				`query` : str
					The query to perform.
				`queryLang` : str
					The URI of a query language.
			:Returns: TODO: to write!
			:Raises `CanNotException`: TODO: to write!
		"""
		
		result = dict()
		
		it = self.executeQuery(query, queryLang)
		
		# query is a SELECT query.
		if it.isBinding():
			
			bindings = it.bindingNames()
			logger.debug("SELECT query, bindings are %s" % bindings)
			result["type"] = "SELECT"
			result["variables"] = bindings
			result["results"] = [] # not a set, or results appearing multiple times (this is possible) will only be added once!
			
			while it.next():
				this_result = map(lambda elt: it.current()[0][elt][1], bindings)
				result["results"].append(this_result)
			
			return result
		
		# query is a ASK query.
		if it.isBool():
			raise CanNotException("Can not get a displayable result for a ASK query. Not available yet.")
		
		# query is a CONSTRUCT query.
		if it.isGraph():
			raise CanNotException("Can not get a displayable result for a CONTRUCT query. Not available yet.")
		
############################################################
	
	# Statement:
	# Node "resource" (subject) - the URI of the element: NODE_RESOURCE
	# Node "relation" (predicate) - #comment, #tag, ...: NODE_RESOURCE
	# Node "object" (other resource or literal value) - resource or value: NODE_RESOURCE | NODE_LITERAL
	# TODO: Node "context" (storage graph) - resource or empty (emptyNode) for default graph ???
	
	def createStatement(self, subject_uri, predicate_type, object_value="", object_language=None):
		""" Creates a soprano statement, a quadruple of the form : [subject_uri, predicate_type, object_value, DEFAULT_ONTOLOGY_URI]. To create a "pattern" statement, give "?" as paramater for subject_uri, predicate_type or object_value. For example, a statement created by my_interface.createStatement("http://www.cuil.com/", RDF_TYPE, "?") will match any statement that has cuil.com as its first node and the RDF_TYPE property as its second one.
			:Parameters:
				`subject_uri` : str
					The URI that will be subject of the statement. Passing "?" as subject_uri will have an empty node registered as the first node of the result statement. This can be used to match patterns for removing multiple statements, for example.
				`predicate_type` : str
					The URI that will be the predicate (relation, property) of the statement. Passing "?" as predicate_type will have an empty node registered as the second node of the result statement.
				`object_value` : str
					The URI that will be the object of the statement. Passing "?" as object_value will have an empty node registered as the third node of the result statement.
				`object_language` : str
					Defines the language of the object. If set to a value, the object node will be a literal node of the given type. If it is not set, thus remains to None, the object node will be resource_node.
			:Returns: The soprano statement, ready to use ;).
		"""
		
		logger.debug("createStatement(%s, %s, %s, %s)" % (subject_uri, predicate_type, object_value, object_language))
		
		s = ""
		
		resource = None
		if subject_uri == "?":
			resource = EMPTY_NODE
		else:
			resource = dbus.Struct([NODE_RESOURCE, subject_uri, s, s])
			
		relation = None
		if predicate_type == "?":
			relation = EMPTY_NODE
		else:
			relation = dbus.Struct([NODE_RESOURCE, predicate_type, s, s])
		
		object = None
		if object_value == "?":
			object = EMPTY_NODE
		elif object_language == None:
			# the object node is a resource
			object = dbus.Struct([NODE_RESOURCE, object_value, s, s])
		else:
			# the object node is a literal value
			object = dbus.Struct([NODE_LITERAL, object_value, s, object_language])
			
		# TODO: an empty node for the context ?
		#context = EMPTY_NODE
		context = dbus.Struct([NODE_RESOURCE, DEFAULT_ONTOLOGY_URI, s, s])
		
		#print statement
		return dbus.Struct([resource, relation, object, context])
		
############################################################

	def registerStatement(self, subject_uri, predicate_type, object_value="", object_language=None):
		""" Registers a soprano statement in the database. The parameters are used to construct a statement with the createStatement() method, then it is stored in the soprano database.
			:Parameters:
				`subject_uri` : str
					The URI that will be subject of the statement.
				`predicate_type` : str
					The URI that will be the predicate (relation, property) of the statement.
				`object_value` : str
					The URI that will be the object of the statement.
				`object_language` : str
					Defines the language of the object. If set to a value, the object node will be a literal node of the given type. If it is not set, thus remains to None, the object node will be resource_node.
			:Returns: 0
		"""
		
		logger.debug(str(self.model) + ".registerStatement")
		
		statement = self.createStatement(subject_uri, predicate_type, object_value, object_language)
		
		logger.debug(str(statement))
		
		error_code = self.model.addStatement(statement)
		
		return 0
		
############################################################

	def deleteStatement(self, subject_uri, predicate_type, object_value="", object_language=None):
		""" Deletes a soprano statement from the database. The parameters are used to construct a statement with the createStatement() method, then this statement is removed from the soprano database.
			:Parameters:
				`subject_uri` : str
					The subject of the statement.
				`predicate_type` : str
					The predicate (relation, property) of the statement.
				`object_value` : str
					The object of the statement.
				`object_language` : str
					The language of the object. If set to a value, the object node is a literal node of the given type. If it is not set, thus remains to None, the object node is resource_node.
			:Returns: 0
		"""
		
		logger.debug("deleteStatement(%s, %s, %s, %s)" % (subject_uri, predicate_type, object_value, object_language))
		
		statement = self.createStatement(subject_uri, predicate_type, object_value, object_language)
		error_code = self.model.removeStatement(statement)
		
		return 0
	
############################################################

	def deleteAllStatements(self, subject_uri, predicate_type, object_value="", object_language=None):
		""" Deletes all soprano statements matching the given "pattern" from the database. The parameters are used to construct a statement with the createStatement() method, then all statements matching this statement. See the createStatement() method documentation for more information.
			:Parameters:
				`subject_uri` : str
					The subject of the statement.
				`predicate_type` : str
					The predicate (relation, property) of the statement.
				`object_value` : str
					The object of the statement.
				`object_language` : str
					The language of the object. If set to a value, the object node is a literal node of the given type. If it is not set, thus remains to None, the object node is resource_node.
			:Returns: 0
		"""
		
		logger.debug(str(self.model) + ".deleteAllStatements")
		
		statement = self.createStatement(subject_uri, predicate_type, object_value, object_language)
		error_code = self.model.removeAllStatements(statement)
		
		return error_code

############################################################

	def getImage(self, resource_uri, property_uri):
		""" Gets the image associated to the given resource by the given property in the database.
			:Parameters:
				`resource_uri` : str
					The URI of the resource we want to retrieve the image of.
				`property_uri` : str
					The property (function here) used to retrieve the image of resource_uri.
			:Returns: The wanted image - str. None if the given resource has no image by the given property in the database.
			:Raises `DatabaseIncoherenceException`: if the given resource has more than one image by the given property.
		"""
		
		query = "SELECT * WHERE { <" + resource_uri + "> <" + property_uri + "> ?elt }"
		elts = self.executeQuery(query)
		
		my_elt = None
		if elts.next(): # resource_uri has an associated element
			my_elt = elts.current()[0]["elt"][1]
		
		if elts.next():
			my_second_elt = elts.current()[0]["elt"][1]
			elts.close()
			
			raise DatabaseIncoherenceException("\"" + resource_uri + "\" has more than one associated element by the property \"" + property_uri + "\" (at least \"" + my_elt + "\" and \"" + my_second_elt + "\").")
		
		elts.close()
		
		return my_elt

############################################################

	def getAntecedent(self, property_uri, object_uri):
		""" Gets the antecedent associated to the given object by the given property in the database.
			:Parameters:
				`property_uri` : str
					The property (function here) used to retrieve the antecedent of object_uri.
				`object_uri` : str
					The URI of the object we want to retrieve the antecedent of.
			:Returns: The wanted antecedent - str. None if the given resource has no antecedent by the given property in the database.
			:Raises `DatabaseIncoherenceException`: if the given resource has more than one antecedent by the given property.
		"""
		
		query = "SELECT * WHERE { ?elt <%s> <%s> }" % (property_uri, object_uri)
		elts = self.executeQuery(query)
		
		my_elt = None
		if elts.next(): # object_uri has an associated element
			my_elt = elts.current()[0]["elt"][1]
		
		if elts.next():
			my_second_elt = elts.current()[0]["elt"][1]
			elts.close()
			
			raise DatabaseIncoherenceException("\"" + object_uri + "\" has more than one antecedent by the property \"" + property_uri + "\" (at least \"" + my_elt + "\" and \"" + my_second_elt + "\").")
		
		elts.close()
		
		return my_elt

############################################################

	def setImage(self, resource_uri, property_uri, image, image_language=None):
		""" Sets the image associated to resource_uri by property_uri in the database. This means that any previously existing image is deleted, and only then the new image is registered. This is useful for function properties.
			:Parameters:
				`resource_uri` : str
					The URI of the resource we want to retrieve the image of.
				`property_uri` : str
					The property (function here) used to retrieve the image of resource_uri.
				`image` : str
					The URI that will be the image (object) of resource_uri by property_uri.
				`image_language` : str
					Defines the language of the image. If set to a value, the image will be registered as a literal node of the given type. If it is not set, thus remains to None, the image will be registered as a resource.
			:Returns: 0
		"""
		
		error_code = self.removeImage(resource_uri, property_uri)
		error_code = self.registerStatement(resource_uri, property_uri, image, image_language)
		
		return 0

############################################################

	# This method deletes every image(s) of resource_uri by property_uri.
	def removeImage(self, resource_uri, property_uri):
		""" Removes the image of resource_uri by property_uri. Will in fact remove every existing images, but this is often used in a functional way (only one image).
			:Parameters:
				`resource_uri` : str
					The URI of the resource we want to remove the image of.
				`property_uri` : str
					The considered property.
			:Returns: 0
		"""
		
		error_code = self.deleteAllStatements(resource_uri, property_uri, "?")
		
		return 0

############################################################

	def getPimosInversePropertyOf(self, property_uri):
		""" Gets the inverse property URI for property_uri.
			:Parameters:
				`property_uri` : str
					The URI of the property we want to get the inverse of.
			:Returns: The wanted inverse_property. None if the given property has no inverse property in the database.
			:Raises `DatabaseIncoherenceException`: if there is more than one inverse property for that property in the database.
		"""
		
		inverse_property_uri = self.getImage(property_uri, PROTEGE_INVERSEPROPERTY)
		
		if inverse_property_uri == None:
			return self.getAntecedent(PROTEGE_INVERSEPROPERTY, property_uri)
		else:
			return inverse_property_uri

############################################################

	def instanceOf (self, resource_uri, type_uri):
		""" Tells whether resource_uri is of type_uri, or if its type derives from (see derivesFrom() method) type_uri.
			:Parameters:
				`resource_uri` : str
					The URI of the resource we want to test.
				`type_uri` : str
					The URI if the requested type.
			:Returns: True if resource_uri is an instance of type_uri (in this meaning), False otherwise.
		"""
		resource_type = self.getImage(resource_uri, RDF_TYPE)
		logger.debug("interface.instanceOf(), %s has rdf:type %s." % (resource_uri, resource_type))
		
		if resource_type == None:
			return False
		
		return self.derivesFrom(resource_type, type_uri)

############################################################

	def derivesFrom (self, child_type_uri, parent_type_uri):
		""" Tells whether child_type derives from parent_type. Derivation at degree zero works, i.e. if the child and parent are equal, derivesFrom() returns True. The derivation is an object-derivation here: the inheritance is detected via the rdfs:subClassOf property.
			/!\ The method does not care about possible database incoherence causing cycles in the inheritance graph, resulting in an infinite loop when calling this function. Further implementations may consider this checking.
			:Parameters:
				`child_type_uri` : str
					The URI of an RDF_TYPE treated as the child type.
				`parent_type_uri` : str
					The URI of an RDF_TYPE treated as the parent type.
			:Returns: True if resource_uri is derives from type_uri, i.e. if there is an "RDFS_SUBCLASSOF-path" between the child and the parent, False otherwise.
		"""
		
		if child_type_uri+" "+parent_type_uri in self.derivationTable:
			logger.debug("derivesFrom(hm) = "+str(self.derivationTable[child_type_uri+" "+parent_type_uri]))
			return self.derivationTable[child_type_uri+" "+parent_type_uri]
		
		if child_type_uri == parent_type_uri:
			logger.debug("derivesFrom(c=p) = True")
			return True
		
		t1 = datetime.today()
		query = "SELECT * WHERE { <" + child_type_uri + "> <" + RDFS_SUBCLASSOF + "> ?type }"
		parent_types = self.executeQuery(query)
		t2 = datetime.today()
		logger.debug("query time="+str(t2-t1))
		
		while parent_types.next():
			parent_type = parent_types.current()[0]["type"][1]
			self.derivationTable[child_type_uri+" "+parent_type] = True
			if self.derivesFrom(parent_type, parent_type_uri):
				parent_types.close()
				return True
		
		parent_types.close()
		
		self.derivationTable[child_type_uri+" "+parent_type_uri] = False
		logger.debug("derivesFrom(fail) = False")
		return False
		
############################################################

	# Checks whether the given context is registered in the database (as an Ontology or InstanceBase)
	def getContextType(self, context_uri):
		""" Gets the context type of context_uri.
			:Parameters:
				`context_uri` : str
					The URI of the considered context.
			:Returns: NRL_INSTANCEBASE or NRL_ONTOLOGY, depending on that context type. None if context_uri does not have any type.
			:Raises `DatabaseIncoherenceException`: if the retrieved context type exists and is neither NRL_INSTANCEBASE nor NRL_ONTOLOGY.
		"""
		
		context_type = self.getImage(context_uri, RDF_TYPE)
		
		if context_type == None:
			return None
		elif [NRL_INSTANCEBASE, NRL_ONTOLOGY].count(context_type) == 0:
			raise DatabaseIncoherenceException("The context \"" + context_uri + "\" has type \"" + context_type + "\", which is neither nrl:InstanceBase nor nrl:Ontology, the only two context types allowed.")
		else:
			return context_type

############################################################

	# Registers the context with the given context uri and type.
	def createContext(self, context_uri, context_type):
		""" Creates context_uri with context_type. The functionnalities about contexts (= graphs = fourth node of any statement) management are very few and not that interesting. One of the reasons is that some things are (still) not very clear in the Nepomuk project, like the identification of the user environment: how to name ontologies/instance bases storing user information? how to name his or her own-defined properties, objects? The current solution is very basic and based upon the user name (defined in constants.py): every information is registered in <nepomuk:user@example.com/resources/ontologies/own>, and named in the same manner. In this case, the createContext() method will be called once, when this context does not exist yet.
			:Parameters:
				`context_uri` : str
					The URI of the context to create.
				`context_type` : str
					The URI of an RDF_TYPE giving the type of the context to create.
			:Returns: 0
			:Raises `CanNotException`: if context_uri already exists.
		"""
		
		# query the database to know if the graph/context where it will be stored already exists as a Ontology or InstanceBase.
		existing_context_type = self.getContextType(context_uri)
		
		if existing_context_type != None:
			raise CanNotException("The context \"" + existing_context_type + "\" already exists. Can not create it.")
		
		error_code = self.registerStatement(context_uri, RDF_TYPE, context_type)
		
		return 0
	
############################################################

	# Returns a set with all children from the parents given, at whatever level (children, grand-children, etc.).
	def getChildrenOf(self, parent_elements, downing_property, ontologies=None):
		""" Gets the children of the given parent_elements, at any derivation level.
			:Parameters:
				`parents_elements` : list(str)
					The list of URIs that we want to get the children of.
				`downing_property` : str
					The URI of an RDF_PROPERTY used to go down in the "inheritance tree". This is the property used to retrieve the children of a parent.
				`ontologies` : set(str)
					A set of ontologies that is used to restrict the number of results: only the children registered as children of the parent_elements by downing_property IN THESE ONTOLOGIES will be retrieved. if omitted, or set to None, there will not be any restriction on the ontologies.
			:Returns: The children of the given parents - set(str), including the parents themselves.
		"""
		
		self.children = set(parent_elements)
		self.getChildrenOfRec(parent_elements, downing_property, ontologies)
		
		return self.children

############################################################

	def getChildrenOfRec(self, parent_elements, downing_property, ontologies):
		""" Recursive function that get the children of the given parent_elements, at any derivation level. Should not be used directly, rather call getChildrenOf.
			:Parameters:
				`parents_elements` : list(str)
					The list of URIs that we want to get the children of.
				`downing_property` : str
					The URI of an RDF_PROPERTY used to go down in the "inheritance tree". This is the property used to retrieve the children of a parent.
				`ontologies` : set(str)
					A set of ontologies that is used to restrict the number of results: only the children registered as children of the parent_elements by downing_property IN THESE ONTOLOGIES will be retrieved. if omitted, or set to None, there will not be any restriction on the ontologies.
			:Returns: The children of the given parents - set(str), including the parents themselves.
		"""
		
		new_children = set()
		
		for parent_elt in parent_elements:
			
			redundancies = 0
			
			# retrieve the children of this parent
			query = None
			if ontologies == None:
				query = "SELECT ?child WHERE { ?child <" + downing_property + "> <" + parent_elt + "> }"
			else:
				query = "SELECT ?child WHERE { GRAPH ?onto { ?child <" + downing_property + "> <" + parent_elt + "> } FILTER (" + bool_expr("onto", ontologies) + ") }"
				logger.log(logging.DEBUG+2, "query = %s", query)
			
			childrenIt = self.executeQuery(query)
			
			while childrenIt.next():
				child = childrenIt.current()[0]["child"][1]
				if child in self.children:
					redundancies += 1
				else:
					new_children.add(child)
					self.children.add(child)
			
			logger.log(logging.DEBUG+1, "redundancies for "+parent_elt[len(parent_elt)-10:len(parent_elt)]+" = "+str(redundancies))
			childrenIt.close()
		
		if new_children != set():
			self.getChildrenOfRec(new_children, downing_property, ontologies)

############################################################

	def getAllNonPropertyObjects(self, filterrr=None):
		""" Gets all the Nepomuk objects from the database that are not properties, possibly filterrred on their id/uri by a string.
			:Parameters:
				`filterrr` : str
					A string that is used to filter the results and get less of them, more precise ones. If filterrr is omitted, or set to None, there will not be any filtering.
			:Returns: The wanted Nepomuk objects - set(str).
		"""
		
		time = datetime.today()
		query = None
		if filterrr == None:
			query = "SELECT ?res WHERE { ?res <%s> ?type FILTER (str(?type) != <%s>) }" % (RDF_TYPE, RDF_PROPERTY)
		else:
			query = "SELECT ?res WHERE { ?res <%s> ?type FILTER ((str(?type) != <%s>) && regex(str(?res), \"%s\", 'i')) }" % (RDF_TYPE, RDF_PROPERTY, filterrr)
		
		print "query = %s" % (query,)
		resources = self.executeQuery(query)
		resources_res = set()
		
		c = 0
		while resources.next():
			resource = resources.current()[0]["res"][1]
			resources_res.add(resource)
			if c >= 25: # too many results
				break
		
		resources.close()
		
		logger.log(logging.DEBUG+3, "getAllNonPropertyObjects() took %s" % (datetime.today() - time),)
		
		return resources_res

############################################################

	def getAllTypes(self, filterrr=None):
		""" Gets all the RDF_TYPEs existing in database, but stops at 25 results for efficiency reasons. This number could be set as a constants, or another way of getting interesting results could be implemented.
			:Parameters:
				`filterrr` : str
					A string that is used to filter the results and get less of them, more precise ones. If filterrr is omitted, or set to None, there will not be any filtering.
			:Returns: The wanted types - set(str).
		"""
		
		time = datetime.today()
		query = None
		if filterrr == None:
			query = "SELECT ?type WHERE { ?res <%s> ?type }" % (RDF_TYPE)
		else:
			query = "SELECT ?type WHERE { ?res <%s> ?type FILTER regex(str(?type), \"%s\", 'i') }" % (RDF_TYPE, filterrr)
		
		types = self.executeQuery(query)
		types_res = set()
		
		c = 0
		while types.next():
			my_type = types.current()[0]["type"][1]
			types_res.add(my_type)
			if c >= 25: # too many results
				break
		
		types.close()
		
		logger.log(logging.DEBUG+3, "getAllTypes() took %s" % (datetime.today() - time),)
		
		return types_res

############################################################

	def getDocument(self, resource_uri):
		""" Gets the document corresponding to resource_uri. For example, getDocument("http://www.cuil.com/") will give you the identifier of the PIMO_DOCUMENT represented by cuil.com, if it exists.
			:Parameters:
				`resource_uri` : str
					The URI that we want to get the document of.
			:Returns: The document identifier corresponding to resource_uri.
		"""
		
		return self.getAntecedent(PIMO_GROUNDINGOCCURRENCE, resource_uri)

############################################################

	def documentChecking(self, document_uri):
		""" Checks if document_uri is actually registered in the database as a PIMO_DOCUMENT. It raises an exception if it is not.
			:Parameters:
				`document_uri` : str
					The URI of the document we want to check.
			:Returns: None
			:Raises `CanNotException`: if document_uri is not an instance of PIMO_DOCUMENT.
		"""
		
		# Check that document_uri actually represents a document.
		if not self.instanceOf(document_uri, PIMO_DOCUMENT):
			raise CanNotException("The element %s is not an instance of %s. You must \"registerAndReify\" it before you can work on it." % (document_uri, PIMO_DOCUMENT))

############################################################

	# Further programming of this class should take into account the possibilities of automatic properties addings described at http://www.dfki.uni-kl.de/~sauermann/2006/01-pimo-report/pimOntologyLanguageReport.html#ch-AutomaticCreationofThingsfromResourceManifestations (available on the 2008-06-19).
	
	# Returns the URI of the Thing that represents the given resource.
	def registerAndReify(self, resource_uri, resource_type, resource_name, resource_thing_type=PIMO_DOCUMENT):
		""" registerAndReify() creates the representation of the given resource_uri and then reifies it, i.e. creates a pimo:Document (or subclass) corresponding to it. The reification aims at registering information about an abstract concept, beginning with a name. That name (and other meta-data) will be bound to the abstract concept, and the only link between the website and this information is a statement saying that the website is an occurrence (PIMO_GROUNDINGOCCURRENCE) of this abstract concept.
			:Parameters:
				`resource_uri` : str
					The resource to "registerAndReify", URI of a web page for example.
				`resource_type` : str
					Instance of RDF_TYPE given by the programmer of the calling method, depending on wether the resource is a web page (NFO_WEBSITE in that case, for example), an e-mail, a file, etc.
				`resource_name` : str
					The name that is going to be given to that element (regardless to its type).
				`resource_thing_type` : str
					The type of the abstract concept, has to derive from PIMO_DOCUMENT.
			:Returns: The URI (identifier) of the document, reification of the resource_uri.
			:Raises `TypeError`: if resource_uri is already registered in the database and has a type different from the given resource_type.
		"""
		
		logger.debug("registerAndReify()")
		
		# a) Check that, if the resource_uri is already registered, its type is the same as the one given here.
		my_type = self.getImage(resource_uri, RDF_TYPE)
		if my_type != None and my_type != resource_type:
			raise TypeError("\"" + resource_uri + "\" already has type \"" + my_type + "\" in database, so you can not use it with type \"" + resource_type + "\".")
		
		# 1. Register the resource as a "manifestation" of the given resource_type.
			# secured by checking a)
		error_code = self.registerStatement(resource_uri, RDF_TYPE, resource_type)
		
		# Retrieve the pimo:Document having this URI as its groudingOccurrence, if it already exists.
		document_uri = self.getAntecedent(PIMO_GROUNDINGOCCURRENCE, resource_uri)
		logger.debug("document_uri = %s" % document_uri)
		
		# b) "Kind of" checking.
		if document_uri != None:
			logger.debug("[%s, pimo:groudingOccurrence, %s] already exists" % (document_uri, resource_type))
			# 2. SET the label for the pimo:Document.
			# secured by the fact that we SET and NOT ADD the label statement (will erase the (possibly existing) previous label).
			error_code = self.setImage(document_uri, NAO_PREFLABEL, resource_name, XMLSCHEMA_STRING)
			return document_uri
		
		document_uri = self.getUniqueId()
		
		
		# 2. SET the label for the pimo:Document.
		# secured by the fact that we SET and NOT ADD the label statement (will erase the (possibly existing) previous label).
		error_code = self.setImage(document_uri, NAO_PREFLABEL, resource_name, XMLSCHEMA_STRING)
		
		# The following part is only called when first creating the pimo:Document corresponding to the given resource_uri.
		
		# 3. Register the resource as a pimo:Thing (or derived type).
			# secured by checking c)
		error_code = self.registerStatement(document_uri, RDF_TYPE, resource_thing_type)
		
		# 4. Link the URI and pimo:Document with the groundingOccurrence property.
		error_code = self.registerStatement(document_uri, PIMO_GROUNDINGOCCURRENCE, resource_uri)
		
		# 5. Register the date when this document is first created.
		# TODO: insert thr good programmer's note here.
		date = getDateTime()
		error_code = self.registerStatement(document_uri, NAO_CREATED, date, XMLSCHEMA_STRING)
		
		return document_uri









